package org.drl.tvkit.util;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.zip.GZIPInputStream;

import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.HttpResponseInterceptor;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.entity.HttpEntityWrapper;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.text.format.DateUtils;

/**
 * @author dai.rui.lin
 * 
 */
public final class HttpHelper {

	private static final int MAC_CONNECT = 2;

	public final static String readHttpResult(String urlStr) {
		String mResult = null;
		int mCount = 0;
		while (mCount < MAC_CONNECT) {
			mResult = onHttpResult(urlStr);
			if (mResult != null) {
				mCount = 4;
				break;
			} else {
				mCount++;
			}
		}
		return mResult;
	}

	public final static String readHttpResult(String urlStr, int ctime,
			int rtime) {
		String mResult = null;
		int mCount = 0;
		while (mCount < MAC_CONNECT) {
			mResult = onHttpResult(urlStr, null, ctime, rtime);
			if (mResult != null) {
				mCount = 4;
				break;
			} else {
				mCount++;
			}
		}
		return mResult;
	}

	public final static String readHttpResult(String urlStr, int ctime,
			int rtime, final int _CON_COUNT) {
		String mResult = null;
		int mCount = 0;
		while (mCount < _CON_COUNT) {
			mResult = onHttpResult(urlStr, null, ctime, rtime);
			if (mResult != null) {
				mCount = _CON_COUNT * 2;
				break;
			} else {
				mCount++;
			}
		}
		return mResult;
	}
	public static final int HTTP_READ_TIMEOUT = 25*1000;
	public static final int HTTP_CONNECT_TIMEOUT = 8*1000;
	private static String onHttpResult(String urlStr) {
		if (urlStr == null) {
			return null;
		}
		urlStr = urlStr.trim().replaceAll("\\s", "");
		String mUrl = urlStr;
		if (!urlStr.startsWith("http://")) {
			urlStr = "http://" + urlStr;
		}
		StringBuffer dataBuffer = new StringBuffer();
		BufferedReader br = null;
		try {
			URL url = new URL(mUrl);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setReadTimeout(HTTP_READ_TIMEOUT);
			conn.setConnectTimeout(HTTP_CONNECT_TIMEOUT);
			conn.setUseCaches(false);
			conn.setDoInput(true);
			conn.connect();
			br = new BufferedReader(
					new InputStreamReader(conn.getInputStream()));
			String item = null;
			while ((item = br.readLine()) != null) {
				dataBuffer.append(item);
			}
			br.close();
			br = null;
			conn.disconnect();
			return dataBuffer.toString();
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				if (br != null)
					br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	private static String onHttpResult(String urlStr, String params, int ctime,
			int rtime) {
		if (urlStr == null) {
			return null;
		}
		urlStr = urlStr.trim().replaceAll("\\s", "");
		String mUrl = urlStr;
		if (!urlStr.startsWith("http://")) {
			urlStr = "http://" + urlStr;
		}
		StringBuffer dataBuffer = new StringBuffer();
		BufferedReader br = null;
		try {
			if (StringUtil.isNotNull(params)) {
				mUrl = mUrl + "&" + params;
			}
			URL url = new URL(mUrl);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setRequestMethod("GET");
			conn.setReadTimeout(rtime);
			conn.setConnectTimeout(ctime);
			conn.setUseCaches(false);
			conn.setDoInput(true);
			conn.connect();
			br = new BufferedReader(
					new InputStreamReader(conn.getInputStream()));
			String item = null;
			while ((item = br.readLine()) != null) {
				dataBuffer.append(item);
			}
			br.close();
			br=null;
			conn.disconnect();
			return dataBuffer.toString();
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception ex) {
			ex.printStackTrace();
		} finally {
			try {
				if (br != null)
					br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	final public static byte[] readStream(InputStream inStream)
			throws Exception {
		ByteArrayOutputStream outstream = new ByteArrayOutputStream();
		byte[] buffer = new byte[1024];
		int len = -1;
		while ((len = inStream.read(buffer)) != -1) {
			outstream.write(buffer, 0, len);
		}
		outstream.close();
		inStream.close();

		return outstream.toByteArray();
	}
	final public static String readStreamLine(InputStream inStream)
			throws Exception {
		StringBuffer _sb = new StringBuffer();
		BufferedReader input = new BufferedReader(new InputStreamReader(inStream));  
		String line = null;  
		while((line = input.readLine()) != null) {  
		    _sb.append(line).append("/n");
		}  
		input.close();
		inStream.close();
		
		return _sb.toString();
	}

	public final static byte[] readHttpResultBytes(String urlStr) {
		urlStr = urlStr.trim().replaceAll("\\s", "");
		String mUrl = urlStr;
		if (!urlStr.startsWith("http://")) {
			urlStr = "http://" + urlStr;
		}
		byte bytes[] = null;
		InputStream br = null;
		try {
			URL url = new URL(mUrl);
			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setReadTimeout(HTTP_READ_TIMEOUT);
			conn.setConnectTimeout(HTTP_CONNECT_TIMEOUT);
			conn.setRequestMethod("GET");
			conn.setUseCaches(false);
			conn.setDoInput(true);
			conn.connect();
			br = conn.getInputStream();
			bytes = readStream(br);
			
			conn.disconnect();
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (br != null)
					br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return bytes;
	}
	/**
	 * 格式化文件名字
	 * 
	 * @param url
	 * @return
	 */
	public final static String forrmatImageUrl(String url) {
		String key = toEncryptedName(url);
		String extName = FileUtils.getExtFileName(url);
		StringBuffer buf = new StringBuffer();
		buf.append(key).append(extName);
		return buf.toString();
	}

	/**
	 * bytes[]转换成Hex字符�?可用于URL转换，IP地址转换.
	 */
	final public static String bytesToHexString(byte[] bytes) {
		// http://stackoverflow.com/questions/332079
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < bytes.length; i++) {
			String hex = Integer.toHexString(0xFF & bytes[i]);
			if (hex.length() == 1) {
				sb.append('0');
			}
			sb.append(hex);
		}
		return sb.toString();
	}

	final public static String toEncryptedName(String str) {
		String cacheKey = str;
		MessageDigest mDigest;
		try {
			mDigest = MessageDigest.getInstance("SHA-1");
			mDigest.update(str.getBytes());
			cacheKey = bytesToHexString(mDigest.digest());
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (Exception ex) {
			ex.printStackTrace();
		}

		return cacheKey;
	}

	public static final int defaultConnectTimeou = 10 * 1000;
	public static final int defaultReadTimeout = 10 * 1000;

	public final static boolean startHttpAsClient(String urlStr, String params,
			int connectTimeou, int readTimeout, Bundle otherParams) {
		L.d("HttpHelper", "doGet : url:" + urlStr + "|params:" + params
				+ "|connectTimeou:" + connectTimeou + "|readTimeout:"
				+ readTimeout);
		boolean succ = false;
		if (connectTimeou < 0) {
			connectTimeou = defaultConnectTimeou;
		}
		if (readTimeout < 0) {
			readTimeout = defaultReadTimeout;
		}

		URL url = null;
		HttpURLConnection httpurlconnection = null;
		try {
			if (StringUtil.isNotNull(params)) {
				urlStr = urlStr + "&" + params;
			}
			url = new URL(urlStr);

			httpurlconnection = (HttpURLConnection) url.openConnection();
			httpurlconnection.setRequestMethod("GET");
			httpurlconnection.setConnectTimeout(connectTimeou);
			httpurlconnection.setReadTimeout(readTimeout);
			httpurlconnection.setUseCaches(false);
			httpurlconnection.connect();
			int code = httpurlconnection.getResponseCode();

			if (code == 200) {
				succ = true;
			}

		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return succ;

	}
	
	
	final public static String getHttpDataAsString(Context context, String url,int ctime,int rtime)
			throws ClientProtocolException, IOException {
		byte bytes[] = null;
		final HttpClient httpClient = HttpHelper.getHttpClient(context.getApplicationContext(),ctime,rtime);
		final HttpResponse resp = httpClient.execute(new HttpGet(url));
		final HttpEntity entity = resp.getEntity();

		final int statusCode = resp.getStatusLine().getStatusCode();
		if (statusCode != HttpStatus.SC_OK || entity == null) {
			return null;
		}
		bytes = EntityUtils.toByteArray(entity);
		if (bytes != null) {
			return new String(bytes);
		} else {
			return null;
		}
	}
	
	@SuppressWarnings("unused")
	private static final int SECOND_IN_MILLIS = (int) DateUtils.SECOND_IN_MILLIS;

	private static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding";
	private static final String ENCODING_GZIP = "gzip";
	
	final public static HttpClient getHttpClient(Context context,int ctime,int rtime) {
		final HttpParams params = new BasicHttpParams();

		// Use generous timeouts for slow mobile networks
		HttpConnectionParams
				.setConnectionTimeout(params,ctime);
		HttpConnectionParams.setSoTimeout(params,rtime);

		HttpConnectionParams.setSocketBufferSize(params, 8192);
		HttpProtocolParams.setUserAgent(params, buildUserAgent(context));

		final DefaultHttpClient client = new DefaultHttpClient(params);

		client.addRequestInterceptor(new HttpRequestInterceptor() {
			public void process(HttpRequest request, HttpContext context) {
				// Add header to accept gzip content
				if (!request.containsHeader(HEADER_ACCEPT_ENCODING)) {
					request.addHeader(HEADER_ACCEPT_ENCODING, ENCODING_GZIP);
				}
			}
		});

		client.addResponseInterceptor(new HttpResponseInterceptor() {
			public void process(HttpResponse response, HttpContext context) {
				// Inflate any responses compressed with gzip
				final HttpEntity entity = response.getEntity();
				final Header encoding = entity.getContentEncoding();
				if (encoding != null) {
					for (HeaderElement element : encoding.getElements()) {
						if (element.getName().equalsIgnoreCase(ENCODING_GZIP)) {
							response.setEntity(new InflatingEntity(response
									.getEntity()));
							break;
						}
					}
				}
			}
		});

		return client;
	}
	
	/**
	 * Build and return a user-agent string that can identify this application
	 * to remote servers. Contains the package name and version code.
	 */
	final private static String buildUserAgent(Context context) {
		try {
			final PackageManager manager = context.getPackageManager();
			final PackageInfo info = manager.getPackageInfo(
					context.getPackageName(), 0);

			// Some APIs require "(gzip)" in the user-agent string.
			return info.packageName + "/" + info.versionName + " ("
					+ info.versionCode + ") (gzip)";
		} catch (NameNotFoundException e) {
			return null;
		}
	}
	
	/**
	 * Simple {@link HttpEntityWrapper} that inflates the wrapped
	 * {@link HttpEntity} by passing it through {@link GZIPInputStream}.
	 */
	final private static class InflatingEntity extends HttpEntityWrapper {
		public InflatingEntity(HttpEntity wrapped) {
			super(wrapped);
		}

		@Override
		public InputStream getContent() throws IOException {
			return new GZIPInputStream(wrappedEntity.getContent());
		}

		@Override
		public long getContentLength() {
			return -1;
		}
	}

}
